package com.moss.cloud.auth.biz.expand.captcha;

import com.moss.cloud.auth.biz.exception.AuthErrorType;
import com.moss.cloud.auth.biz.utils.AuthHandel;
import com.ramostear.captcha.HappyCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 验证码授权模式
 * @author 瑾年
 * @date 2023年3月27日
 */
@Slf4j
public class CaptchaTokenGranter extends AbstractTokenGranter {

    /**
     * 声明授权者 CaptchaTokenGranter 支持授权模式 captcha
     * 根据接口传值 grant_type = captcha 的值匹配到此授权者
     * 匹配逻辑详见下面的两个方法
     * @see CompositeTokenGranter#grant(String, TokenRequest)
     * @see AbstractTokenGranter#grant(String, TokenRequest)
     */
    private static final String GRANT_TYPE = "captcha";
    private final AuthenticationManager authenticationManager;
    private HttpServletRequest request;

    public CaptchaTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                               OAuth2RequestFactory requestFactory, AuthenticationManager authenticationManager, HttpServletRequest request
    ) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
        this.request = request;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

        Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());

        // 验证码校验逻辑
        String captchaCode = parameters.get("captchaCode");
        log.info("验证码:{}",captchaCode);
        AuthHandel.trueThrow(StringUtils.isBlank(captchaCode)).throwMessage(AuthErrorType.CAPTCHA_EMPTY.getMesg());
        // 从缓存取出正确的验证码和用户输入的验证码比对
        boolean flag = HappyCaptcha.verification(request, captchaCode, true);
        AuthHandel.trueThrow(Boolean.FALSE.equals(flag)).throwMessage(AuthErrorType.CAPTCHA_ERROR.getMesg());
        String username = parameters.get("username");
        String password = parameters.get("password");
        log.info("当前授权用户账号->:{},当前授权用户密码:->{}",username,password);
        // 移除后续无用参数
        parameters.remove("password");
        parameters.remove("captchaCode");

        // 和密码模式一样的逻辑
        Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

        try {
            userAuth = this.authenticationManager.authenticate(userAuth);
        } catch (AccountStatusException var8) {
            throw new InvalidGrantException(var8.getMessage());
        } catch (BadCredentialsException var9) {
            throw new InvalidGrantException(var9.getMessage());
        }
        if (userAuth != null && userAuth.isAuthenticated()) {
            OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
            return new OAuth2Authentication(storedOAuth2Request, userAuth);
        } else {
            throw new InvalidGrantException("无法验证用户身份: " + username);
        }
    }
}
